package proyectotsm;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.WritableRaster;

/**
 * Clase Imagen.java
 *
 * @author juan carlos
 * @author srgank
 * @author gabriel
 */
public class Imagen {

    // Atributos
    /** Buffer de la imagen capturada */
    private BufferedImage bufImage;
    /** Nombre de la imagen */
    private String nomImagen;
    /** Ancho de la imagen */
    private int ancho;
    /** Altura de la imagen */
    private int alto;
    public static final int THRESHOLDbw = 14;
    public static final int Rchannel = 0;
    public static final int Gchannel = 1;
    public static final int Bchannel = 2;
    private int numero;

    /**
     * Constructor sin parametros d ela clase Imagen
     */
    public Imagen() {
        // Constructor vacio
    }

    /**
     * Constructor con parametros de la clase imagen
     * @param nombre nombre de la imagen
     */
    public Imagen(String nombre) {
        nomImagen = nombre;        
    }

    /**
     * Constructor con parametros de la clase imagen
     * @param img buffer de imagen a guardar
     * @param nombre nombre de la imagen
     */
    public Imagen(BufferedImage img, String nombre,int numero) {
        bufImage = img;
        nomImagen = nombre;
        alto = img.getHeight();
        ancho = img.getWidth();
        this.numero = numero;
    }

    /**
     * Devuelve el numero de la imagen
     * @return El numero de la imagen
     */
    public int getNumero() {
        return numero;
    }

    /**
     * Configura el numero de la imagen
     * @param numero El numero de la imagen
     */
    public void setNumero(int numero) {
        this.numero = numero;
    }

    /**
     * Seteador de imagen
     * @param img imagen a setear
     */
    public void setImagen(BufferedImage img) {
        bufImage = img;
    }

    /**
     * Getter del buffer de imagen
     * @return Buffer de imagen
     */
    public BufferedImage getBufferedImagen() {
        return bufImage;
    }

    /**
     * Devolvemos la imagen invertida
     *
     * @return La imagen invertida
     */
    public BufferedImage getInvertedImage() {
        WritableRaster wras_tmp = ((WritableRaster) bufImage.getData());
        int pix[] = new int[wras_tmp.getNumBands()];
        for (int i = 0; i < bufImage.getWidth(); i++) {
            for (int j = 0; j < bufImage.getHeight(); j++) {
                pix = wras_tmp.getPixel(i, j, pix);

                pix[Imagen.Bchannel] = 255 - pix[Imagen.Bchannel];
                pix[Imagen.Rchannel] = 255 - pix[Imagen.Rchannel];
                pix[Imagen.Gchannel] = 255 - pix[Imagen.Gchannel];

                wras_tmp.setPixel(i, j, pix);
            }
        }
        BufferedImage b = new BufferedImage(bufImage.getWidth(), bufImage.getHeight(), bufImage.getType());
        b.setData(wras_tmp);
        return b;
    }

    /**
     * Devolvemos la imagen en sepia
     *
     * @return La imagen en sepia
     */
    public BufferedImage getSepiaImage() {
        WritableRaster wras_tmp = ((WritableRaster) bufImage.getData());
        int pix[] = new int[wras_tmp.getNumBands()];
        for (int i = 0; i < bufImage.getWidth(); i++) {
            for (int j = 0; j < bufImage.getHeight(); j++) {
                pix = wras_tmp.getPixel(i, j, pix);

                int red = pix[Imagen.Rchannel];
                int blue = pix[Imagen.Bchannel];
                int green = pix[Imagen.Gchannel];

                pix[Imagen.Rchannel] = (int) (.189 * blue + .393 * red + 769 * green);
                pix[Imagen.Gchannel] = (int) (.168 * blue + .349 * red + .686 * green);
                pix[Imagen.Bchannel] = (int) (.131 * blue + .272 * red + .534 * green);

                wras_tmp.setPixel(i, j, pix);
            }
        }
        BufferedImage b = new BufferedImage(bufImage.getWidth(), bufImage.getHeight(), bufImage.getType());
        b.setData(wras_tmp);
        return b;
    }

    /**
     * Devuelve la imagen con un valor de limite o lindar
     *
     * @param valor El lindar del threshold
     * @return La imagen con threshold
     */
    public BufferedImage getTherImage(double valor) {
        BufferedImage b = new BufferedImage(bufImage.getWidth(), bufImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);

        ColorConvertOp xformOp = new ColorConvertOp(null);
        xformOp.filter(bufImage, b);

        WritableRaster wras_tmp = ((WritableRaster) b.getData());

        int pix[] = new int[wras_tmp.getNumBands()];
        for (int i = 0; i < bufImage.getWidth(); i++) {
            for (int j = 0; j < bufImage.getHeight(); j++) {
                pix = wras_tmp.getPixel(i, j, pix);

                if (pix[0] > valor) {
                    pix[0] = 255;
                } else {
                    pix[0] = 0;
                }
                wras_tmp.setPixel(i, j, pix);
            }
        }
        b.setData(wras_tmp);
        return b;
    }

    /**
     * Funcion que devuelve la imagen como imagen no como buffer de imagen
     * @return devuelve la imagen
     */
    public Image getImagen() {
        return Toolkit.getDefaultToolkit().createImage(bufImage.getSource());
    }

    /**
     * Obtenemos la imagen a traves de una buffered image
     *
     * @param bf BufferedImage de entrada
     * @return la imagen de salida
     */
    public Image getImagen(BufferedImage bf) {
        return Toolkit.getDefaultToolkit().createImage(bf.getSource());
    }

    /**
     * Seteador del nombre de la imagen
     * @param entrada nombre de la imagen
     */
    public void setNombre(String entrada) {
        nomImagen = entrada;
    }

    /**
     * devuelve el nombre de la imagen
     * @return devuelve el nombre de la imagen
     */
    public String getNombre() {
        return nomImagen;
    }

    /**
     * Funcion que dibuja el la imagen por pantalla
     * @param g pantalla grafica
     */
    public void draw(Graphics g) {
        g.drawImage(bufImage, 0, 0, alto, alto, null);
    }

    /**
     * Funcion que retorna el ancho de imagen
     * @return retorna el ancho de imagen
     */
    public int getAncho() {
        return ancho;
    }

    /**
     * Funcion que devuelve el alto de la imagen
     * @return devuelve el alto de la imagen
     */
    public int getAlto() {
        return alto;
    }

    /**
     * Obtenemos el histograma de la imagen
     *
     * @return El histograma
     */
    public double[][] getHistograma() {
        double[][] hist = new double[256][3];

        WritableRaster wras_tmp = ((WritableRaster) bufImage.getData());
        int pix[] = new int[wras_tmp.getNumBands()];
        for (int i = 0; i < bufImage.getWidth(); i++) {
            for (int j = 0; j < bufImage.getHeight(); j++) {
                pix = wras_tmp.getPixel(i, j, pix);

                hist[pix[Imagen.Bchannel]][0]++;
                hist[pix[Imagen.Rchannel]][1]++;
                hist[pix[Imagen.Gchannel]][2]++;

                wras_tmp.setPixel(i, j, pix);

            }
        }
        return hist;
    }
}
